package com.socodethis.spaceex.gamescreen;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Plane;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.Ray;
import com.socodethis.spaceex.AttackLoader;
import com.socodethis.spaceex.DebugHUD;
import com.socodethis.spaceex.GameUIClass;
import com.socodethis.spaceex.OptionsScreen;
import com.socodethis.spaceex.TileHolder;
import com.socodethis.spaceex.attackHolder;
import com.socodethis.spaceex.buttonClass;
import com.socodethis.spaceex.customGame;
import com.socodethis.spaceex.dungeonGenerator;
import com.socodethis.spaceex.enemyClass;
import com.socodethis.spaceex.playerClass;
import com.socodethis.spaceex.shortestPath;
import com.socodethis.spaceex.skyBox;
import com.socodethis.spaceex.soundHolder;
import com.socodethis.spaceex.spriteAnimate;
import com.socodethis.spaceex.spriteOrganizer;
import com.socodethis.spaceex.textureHolder;
import com.socodethis.spaceex.texturePackerLoader;
import com.socodethis.spaceex.worldGeneratorClass;
import com.socodethis.spaceex.math.cPoint;
import com.socodethis.spaceex.math.cRect;

public class GameScreen implements InputProcessor,Screen {	
	//Texture texture;
	Sprite player, dirtHolder;
	OrthographicCamera cam, backCam, frontCam;
	SpriteBatch batch;	
	//tiledLoader map = new tiledLoader("data/badMap.tmx", "data/");
	Sprite[][] floorSprites, structures;
	ArrayList <spriteOrganizer> spriteList;
	cPoint origin;
	float rotationSpeed;
	final Matrix4 matrix = new Matrix4();	
	final Matrix4 unmatrix = new Matrix4();
	cPoint clicked, size, structSize;
	final Vector3 curr = new Vector3();
	final Vector3 last = new Vector3(-1, -1, -1);
	final Vector3 delta = new Vector3();
	final Plane xzPlane = new Plane(new Vector3(0, 1, 0), 0);
	final Vector3 intersection = new Vector3();
	Sprite lastSelectedTile = null;
	Sprite lastSelectedStructure = null;
	playerClass mainPlay;
	float dirtHeight = 0, dirtWidth=0;
	ArrayList<enemyClass> /*mapEnemies,*/ tempArray;
	attackHolder aHold;
	attackHolder eHold;
	float stateTime;
	textureHolder texture;
	Music gameMusic;
	soundHolder sounds;
	float rotation;
	skyBox sBox;
	GameUIClass gClass;
	boolean pathFinder=false;
	float camWidth, camHeight;
	worldGeneratorClass mapGen;
	AttackLoader currentAttack;
	shortestPath path;
	private boolean deleteFlag;
	private int z,x,i,widthStandard,renderX,renderZ,bar;
	private cPoint currentz = new cPoint(0,0);
	private cPoint pointRenderHolder = new cPoint(0,0);
	private cPoint pointRenderHolder2 = new cPoint(0,0);
	private Vector3 sphereVector = new Vector3(0,0,0);
	private Ray pickRay;
	private Random random = new Random(System.nanoTime());
	private float floorHeight;
	
	 // for pinch-to-zoom
	 int numberOfFingers = 0;
	 int fingerOnePointer;
	 int fingerTwoPointer;
	 float lastDistance = 0;
	 cPoint fingerOne = new cPoint();
	 cPoint fingerTwo = new cPoint();
	
	
	DebugHUD debugHUD;
	
	
	private customGame g;
 
	public GameScreen(customGame game) {
		
		g = game;
		//This is a static test for the dungeon generator
		spriteList = new ArrayList<spriteOrganizer>();
		/*mapEnemies = new ArrayList<enemyClass>();*/
		tempArray = new ArrayList<enemyClass>();
		//These classes need to be implemented in a more elegant manner
		size = new cPoint((float) Math.sqrt(3),2);
		origin = new cPoint(-.1f,.3f);
		structSize = new cPoint(1.3142135f,2.5f);
		rotation=133;
		texture = new textureHolder();
		sBox = new skyBox(texture.backGround(0));
		
		debugHUD = new DebugHUD();
		
				//new Sprite(new Texture(Gdx.files.internal("test_stars1.png"))),
				//new Sprite(new Texture(Gdx.files.internal("test_stars2.png")))
		aHold = new attackHolder(size);
		eHold = new attackHolder(size);
		//Height, width, size of world. Eventually all these things will be done away with
		mapGen = new worldGeneratorClass(g.returnWorld());
		//attackSpeed, attackMovementSpeed, attackRadius, attackRange, attackName
		currentAttack = new AttackLoader(5,20,.1f,5,2,"friendBall");
		
		mainPlay = new playerClass(new spriteAnimate(texture.returnPlayer_lu(false),texture.returnPlayer_lu(true),
				texture.returnPlayer_ld(false),texture.returnPlayer_ld(true)
				, new cPoint(mapGen.getDungeon(mapGen.getIndex()).getPlayer().getX(),mapGen.getDungeon(mapGen.getIndex()).getPlayer().getY())
				,new cPoint(0,0),128,false,.03f),mapGen.getDungeon(mapGen.getIndex()),9);
		
		sounds = new soundHolder();
		sounds.addSound(Gdx.audio.newSound(Gdx.files.internal("sounds/sfx_cat_attack_basic.ogg")));
		
		gameMusic = Gdx.audio.newMusic(Gdx.files.internal("sounds/blasting_off_again.mp3"));
		gameMusic.setVolume(0.1f);
		gameMusic.setLooping(true);   
		gameMusic.play();

		player = new Sprite();
		//player.rotate(30);
		clicked = new cPoint(0,0);
		camWidth = 10;
		camHeight = 10 * (Gdx.graphics.getHeight() / (float)Gdx.graphics.getWidth());
		cam = new OrthographicCamera(camWidth, camHeight);		
		backCam = new OrthographicCamera(camWidth, camHeight);		
		frontCam = new OrthographicCamera(camWidth, camHeight);		
		gClass = new GameUIClass();
		
		sBox.addLayer(new Sprite(new Texture(Gdx.files.internal("test_stars1.png"))), 
				new cPoint(0.1f, 0.0f), new cPoint(backCam.viewportWidth,backCam.viewportHeight));
		sBox.addLayer(new Sprite(new Texture(Gdx.files.internal("test_stars2.png"))), 
				new cPoint(0.01f, 0.0f), new cPoint(backCam.viewportWidth,backCam.viewportHeight));
		
		resetSprites();
		resetCamera();
		
		cam.direction.set(-1, -1, -1);
		cam.near = 1;
		cam.far = 1000;
		cam.zoom += 1;
		cam.position.set(mainPlay.getPosition().getX()+10,10,mainPlay.getPosition().getY()+10);
		matrix.setToRotation(new Vector3(1, 0, 0), 90);
		unmatrix.setToRotation(new Vector3(0, 0, 0), 0);
		rotationSpeed = 0.5f;

		setTiles();
		//cam.position.set(10,10,20);
		batch = new SpriteBatch();
 
		Gdx.input.setInputProcessor(this);
	}
	
	public void checkMenu(){
		if (Gdx.input.isKeyPressed(Keys.MENU) || Gdx.input.isKeyPressed(Keys.M)){
			g.setScreen(new OptionsScreen(g));
		}
	}
	
	@Override
	public boolean keyDown(int keycode) {
		switch(keycode){
		
			//Just a structure class used to define the different properties of an attack. Use the arrow keys to switch
			//attackSpeed, attackMovementSpeed, attackRadius, attackRange, attackName
			case 19:dirtHeight+=.5;System.out.println("Height: "+dirtHeight);/*currentAttack = new AttackLoader(20,50,.25f,3,1,"fireBall");*/break; //up
			case 20:dirtHeight-=.5;System.out.println("Height: "+dirtHeight);/*currentAttack = new AttackLoader(35,90,.05f,7,1,"rocket");*/break;//down
			case 21:dirtWidth+=.5;System.out.println("Width: "+dirtWidth);/*currentAttack = new AttackLoader(25,30,.1f,4,3,"rainbowBall");*/break; //left
			case 22:dirtWidth-=.5;System.out.println("Width: "+dirtWidth);/*currentAttack = new AttackLoader(5,20,.1f,5,2,"friendBall");*/break;//right
			
			case 45:cam.zoom+=.1f;break;
			case 29:cam.zoom-=.1f;break;
			
			/*case 45:if(mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX()-1,
					mainPlay.getPosition().getY()))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX()-1,mainPlay.getPosition().getY()));}break; //q //left
			case 51:if(mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX()+1,
					mainPlay.getPosition().getY()))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX()+1,mainPlay.getPosition().getY()));}break;//w //right
			case 29:if(mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX(),
					mainPlay.getPosition().getY()-1))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX(),mainPlay.getPosition().getY()-1));}break; //a //up
			case 47:if(mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX(),
					mainPlay.getPosition().getY()+1))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX(),mainPlay.getPosition().getY()+1));}break;//s //down*/
			
			
			/*
			case 15:origin = new cPoint(origin.getX(),origin.getY()+.1f);break; //up
			case 9:origin = new cPoint(origin.getX(),origin.getY()-.1f);break;//down
			case 11:origin = new cPoint(origin.getX()-.1f,origin.getY());break; //left
			case 13:origin = new cPoint(origin.getX()+.1f,origin.getY());break;//right
			
			case 19:structSize = new cPoint(structSize.getX(),structSize.getY()+.1f);break; //up
			case 20:structSize = new cPoint(structSize.getX(),structSize.getY()-.1f);break;//down
			case 21:structSize = new cPoint(structSize.getX()-.1f,structSize.getY());break; //left
			case 22:structSize = new cPoint(structSize.getX()+.1f,structSize.getY());break;//right
			
			case 45:cam.zoom+=.1f;break;
			case 29:cam.zoom-=.1f;break;*/
		}
		//System.out.println(cam.zoom);
		
		/*System.out.println(rotation);
		origin.printPoint();
		structSize.printPoint();
		// TODO Auto-generated method stub
		setTiles();*/
		return false;
	}
	@Override
	public boolean keyUp(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean keyTyped(char character) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean touchDown(int x, int y, int pointer, int button) {
		//point.printPoint();
		 // for pinch-to-zoom
		 numberOfFingers++;
		 if(numberOfFingers == 1)
		 {
		        fingerOnePointer = pointer;
		        fingerOne.setPoint(x, y);
		 }
		 else if(numberOfFingers == 2)
		 {
		        fingerTwoPointer = pointer;
		        fingerTwo.setPoint(x, y);
		 
		       float distance = fingerOne.getEucDistance(fingerTwo);
		        lastDistance = distance;
		 }
		return false;
	}
	@Override
	public boolean touchUp(int x, int y, int pointer, int button) {
		last.set(-1, -1, -1);
		
		 // for pinch-to-zoom           
		 if(numberOfFingers == 1)
		 {
		        //Vector3 touchPoint = new Vector3(x, y, 0);
		        //cam.unproject(touchPoint);
		 }
		 numberOfFingers--;
		 
		// just some error prevention... clamping number of fingers (ouch! :-)
		 if(numberOfFingers<0){
		        numberOfFingers = 0;
		 }
		 

		lastDistance = 0;
		
		return false;
	}
	
	private void checkTileTouched() {
		if(!pathFinder){
		if(Gdx.input.justTouched()) {
			pickRay = cam.getPickRay(Gdx.input.getX(), Gdx.input.getY());
			Intersector.intersectRayPlane(pickRay, xzPlane, intersection);
			x = (int)intersection.x;
			z = (int)intersection.z;
			if(x >= 0 && x < (int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX()) && z >= 0 
					&& z < (int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY())) {
				if(lastSelectedTile != null) {
					lastSelectedTile.setColor(mapGen.getColor());
				}
				if(lastSelectedStructure != null) {
					//lastSelectedTile.setColor(1, 1, 1, 1);
					lastSelectedStructure.setColor(1, 1, 1, 1);
					//lastSelectedStructure.setColor(mapGen.getColor());
				}
				//Sprite sprite = floorSprites[x][z];
				//sprite.setColor(1, 0, 0, 1);
				lastSelectedTile = floorSprites[x][z];
				lastSelectedTile.setColor(1, 0, 0, 1);
				
				if(structures[x][z]!=null){
					//Sprite spriteS = structures[x][z];
					//spriteS.setColor(1, 0, 0, 1);
					lastSelectedStructure = structures[x][z];
					lastSelectedStructure.setColor(1, 0, 0, 1);
				}
				//walkAnimation.calcDirection(new cPoint(x, z));
				if(mapGen.canGoThere(mapGen.getIndex(), new cPoint(x,z))){
					mainPlay.moveChar(new cPoint(x, z));
				}
				//walkAnimation.setPosition(new cPoint(x+1, z));
				//player.setPosition(x, z-1);
				//player.setOrigin((player.getX()+player.getWidth()/2), (player.getY()+player.getHeight()/2));
			}
		}
		}else{
		if(Gdx.input.isTouched()){
		// TODO Auto-generated method stub
		cPoint point = new cPoint(Gdx.input.getX(), Gdx.input.getY());
		if(point.inSquare(0, 0, 100, 100) &&
				
				
				mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX()-1,
			mainPlay.getPosition().getY()))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX()-1,mainPlay.getPosition().getY()));} //q //left
		if(point.inSquare((float)Gdx.graphics.getWidth()-100, (float)Gdx.graphics.getHeight()-100, (float)Gdx.graphics.getWidth(), (float)Gdx.graphics.getHeight()) &&
				mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX()+1,
			mainPlay.getPosition().getY()))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX()+1,mainPlay.getPosition().getY()));}//w //right
		
		
		if(point.inSquare((float)Gdx.graphics.getWidth()-100, 0, (float)Gdx.graphics.getWidth(), 100) &&	
				mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX(),
			mainPlay.getPosition().getY()-1))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX(),mainPlay.getPosition().getY()-1));} //a //up
		
		
		if(point.inSquare(0, (float)Gdx.graphics.getHeight()-100, 100, (float)Gdx.graphics.getHeight()) &&
				mapGen.canGoThere(mapGen.getIndex(), new cPoint(mainPlay.getPosition().getX(),
			mainPlay.getPosition().getY()+1))){mainPlay.moveChar(new cPoint(mainPlay.getPosition().getX(),mainPlay.getPosition().getY()+1));}//s //down
		}
		}
	}
	public void resetSprites(){
		floorSprites = new Sprite[(int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX())]
				[(int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY())];
		structures = new Sprite[(int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX())]
				[(int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY())];
	}
	public void resetCamera(){
		cam.position.set(mainPlay.getSmoothPosition().getX()+10,10,mainPlay.getSmoothPosition().getY()+10);
	}
	@Override
	public boolean touchDragged(int x, int y, int pointer) {
		
		if(!pathFinder){
		pickRay = cam.getPickRay(x, y);
		Intersector.intersectRayPlane(pickRay, xzPlane, curr);
 
		if(!(last.x == -1 && last.y == -1 && last.z == -1) && numberOfFingers == 1) {
			pickRay = cam.getPickRay(last.x, last.y);
			Intersector.intersectRayPlane(pickRay, xzPlane, delta);			
			delta.sub(curr);
			//This has to be here so that a bad delta doesn't send the board flying off the screen
			if ((cam.position.x + delta.x)>0
					&& (cam.position.y + delta.y)>0
					&& (cam.position.z + delta.z)>0){
				cam.position.add(delta.x, delta.y, delta.z);
				//System.out.println(cam.position.x+":"+cam.position.y+":"+cam.position.z);
				//System.out.println(mainPlay.getPosition().getX() +":"+mainPlay.getPosition().getY());
			}
		}
		last.set(x, y, 0);
		}else{
			if(numberOfFingers == 2){
				boolean moved = false;
				// for pinch-to-zoom
				if (pointer == fingerOnePointer) {
					if(fingerOne.getEucDistance(new cPoint(x,y)) > 2){
						fingerOne.setPoint(x, y);
						moved = true;
					}
				}
				if (pointer == fingerTwoPointer) {
					if(fingerTwo.getEucDistance(new cPoint(x,y)) > 2){
						fingerTwo.setPoint(x, y);
						moved = true;
					}
				}
				if(moved){
					float distance = fingerOne.getEucDistance(fingerTwo);
					float factor = (distance / lastDistance)/2;
		 
					if (lastDistance > distance) {
						cam.zoom += factor;
					} else if (lastDistance < distance) {
						cam.zoom -= factor;
					}
					// clamps field of view to common angles...
					if (cam.zoom < 1f) cam.zoom = 1f;
					if (cam.zoom > 3f) cam.zoom = 3f;
					lastDistance = distance;
					cam.update();
				}
			}
		}
		return false;
	}
	@Override
	public boolean touchMoved(int x, int y) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean scrolled(int amount) {
		
		/*rotation += amount;
		System.out.println(rotation);
		origin.printPoint();
		structSize.printPoint();
		setTiles();*/
		return false;
	}
	
	//This algorithm took way longer than I would like to admit. Evaluates the diamonds from the top down
	public void returnNextDraw(cPoint current){
		bar = (int) (current.getX() + current.getY());
		if (current.getY()>0 && (current.getX()+1 < mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX())){
			current.setPoint(current.getX()+1, current.getY()-1);
		}else{
			bar++;
			if ((bar < mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY())){
				current.setPoint(0, bar);
			}
			else{
				current.setPoint(bar-(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY()-1), 
						mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY()-1);
			}
		}
	}
	
	public void setCharHeight(){
		pointRenderHolder.setPoint(mainPlay.getPosition().getX(), mainPlay.getPosition().getY());
		floorHeight = mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getHeight();
		mainPlay.setCharPosLevel(floorHeight);
		
		for(i =0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size(); i++){
			pointRenderHolder.setPoint(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY());
			floorHeight = mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getHeight();
			mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setCharPosLevel(floorHeight);
		}
	}
	
	public void printSprites(SpriteBatch batch){
		mainPlay.setRendered(false);
		widthStandard = (int) floorSprites[0][0].getWidth();
		for(i =0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size(); i++){
			mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setRendered(false);
		}
		for(z = 0; z < mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY(); z++) {
			for(x = 0; x < mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX(); x++) {
				sphereVector.set(x, 0, z);
				pointRenderHolder.setPoint(x, z);
				floorHeight = mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getHeight();
				if(cam.frustum.sphereInFrustum(sphereVector, widthStandard)){
					
				dirtHolder = mapGen.getStructureDirt(mapGen.getIndex(), pointRenderHolder).getSprite();
				dirtHolder.setPosition((float) (x-floorHeight+2.5), z-floorHeight+1);
				dirtHolder.draw(batch);
				
				floorSprites[x][z].setPosition(x-floorHeight, z-floorHeight);
				floorSprites[x][z].draw(batch);
				//This is for the structures that are stepped on. Will be expanded later
				if(mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getPropAtIndex(2)
						&& structures[x][z]!=null){
					structures[x][z].setPosition((float) (x+1.5-floorHeight), z-floorHeight);
					structures[x][z].draw(batch);
				}
				}
			}
		}
		currentz.setPoint(0, 0);
		while((currentz.getX() * currentz.getY()) <= (mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY()-1)*
				(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX()-1)){
					renderX=(int) currentz.getX();
					renderZ=(int) currentz.getY();
					sphereVector.set(renderX, 0, renderZ);
					pointRenderHolder.setPoint(renderX, renderZ);
					floorHeight = mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getHeight();
					//if(mapGen.returnPos(mapGen.getIndex(), new cPoint(x,z)) == 0){
					//Only prints what is actually in the camera's view. Mostly for speed
					if(cam.frustum.sphereInFrustum(sphereVector, widthStandard)){
					if(structures[renderX][renderZ]!=null && !mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getPropAtIndex(2)){
						structures[renderX][renderZ].setPosition((float)(renderX+1.5-floorHeight), renderZ-floorHeight);
						//So this is because I was lazy and didn't want to add anything more to the RAM. 
						if(mapGen.getStructureProps(mapGen.getIndex(), pointRenderHolder).getPropAtIndex(4)){
							structures[renderX][renderZ].flip(true, false);
						}
						structures[renderX][renderZ].draw(batch);
						//Flips the image back to it's original position after use
						if(mapGen.getStructureProps(mapGen.getIndex(), pointRenderHolder).getPropAtIndex(4)){
							structures[renderX][renderZ].flip(true, false);
						}
					}
					//}
					if((renderZ+renderX>=mainPlay.getPositionDrawing().getY()+mainPlay.getPositionDrawing().getX())
							&& !mainPlay.getRendered() && mainPlay.returnDirection() != 0 && mainPlay.returnDirection() != 1){
						mainPlay.drawSprites(batch);
						mainPlay.setRendered(true);
					}
					else if((renderZ+renderX>=mainPlay.getPosition().getY()+mainPlay.getPosition().getX())
							&& !mainPlay.getRendered() && (mainPlay.returnDirection() == 0 || mainPlay.returnDirection() == 1)){
						mainPlay.drawSprites(batch);
						mainPlay.setRendered(true);
					}
					for(i =0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size(); i++){
						if(!mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getRendered() 
							 && (renderZ+renderX>=mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPositionDrawing().getY()
							 +mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPositionDrawing().getX())
							 && (mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).returnDirection() != 0 
							 && mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).returnDirection() != 1)){
							mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).drawSprites(batch);
							mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setRendered(true);
						}
						else if((renderZ+renderX>=mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()+
								mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX())
								&& !mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getRendered() 
								&& (mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).returnDirection() == 0 
								|| mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).returnDirection() == 1)){
							mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).drawSprites(batch);
							mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setRendered(true);
						}
					}
					}
			returnNextDraw(currentz);
		}
		for(i = 0; i < aHold.getSize();i++){
			aHold.returnSprite(i, Color.PINK).draw(batch);
		}
		for(i = 0; i < eHold.getSize();i++){
			eHold.returnSprite(i, Color.BLUE).draw(batch);
		}
		if (!mainPlay.getRendered()){
			mainPlay.drawSprites(batch);
		}
		for(i =0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size(); i++){
			if(!mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getRendered()){
				mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).drawSprites(batch);
				mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setRendered(true);
			}
		}
		//System.out.println(mainPlay.returnDirection());
	}
	
	public void checkTiles(){
		//Make sure that the player is stopped if he flips a switch and there is a door in the path
		if(mapGen.getDungeon(mapGen.getIndex()).trackPlayer(mainPlay.getPositionDrawing())){
			//updateTile(mainPlay.getPositionDrawing(),0);
			setTiles();
			path = new shortestPath(mapGen.getDungeon(mapGen.getIndex()).getObstacleMap(),
				mainPlay.getPositionDrawing(), mainPlay.getDestination(),(int)mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX(),
				(int)mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY());
			//If the door is closed and the player is destined to go through it
			if(path.returnPath().size()<2){
				mainPlay.moveChar(new cPoint(mainPlay.getPositionDrawing().getX(),mainPlay.getPositionDrawing().getY()));
			}
		}
		if(mapGen.getDungeon(mapGen.getIndex()).returnBox(mainPlay.getPositionDrawing())){
			if(!mapGen.getDungeon(mapGen.getIndex()).tryingToMoveBox(mainPlay.getPosition(),mainPlay.getPositionDrawing())){
				//Stop the character if he can't move the box
				mainPlay.stopChar();
			}else{
				//Move the box if the character can move the box
				setTiles();
			}
		}
	}
	
	public void checkPlayerDead(){
		if(mainPlay.returnHealth()<1){
			
			mapGen.setCurrentIndex(0);
			
			mainPlay.changeDungeon(mapGen.getDungeon(mapGen.getIndex()),
					new cPoint(mapGen.getDungeon(mapGen.getIndex()).getPlayer().getX(),mapGen.getDungeon(mapGen.getIndex()).getPlayer().getY()));
			aHold.clear();
			eHold.clear();
			mainPlay.resetHealth();
			mainPlay.lostLife();
			setTiles();
			//clear the enemies so that they will be reloaded when the new map is generated
			//mapGen.getDungeon(mapGen.getIndex()).getEnemies().clear();
			
		}
	}
	
	@Override
	public void render(float delta) {
		//System.out.println(g.returnPathfinder()==true?"True":"False");
		//If the player has exited the dungeon and is moving to a new one
		if(mapGen.isExit(mapGen.getIndex(), mainPlay.getPosition()) && !mapGen.justWarped()){
		//For now, all we need to do when a new map is loaded is change the player's position and reload the map
		//into the shortest path algo

			cPoint location = new cPoint(mapGen.checkExit(mapGen.getIndex(), mainPlay.getPosition()));
			mainPlay.changeDungeon(mapGen.getDungeon(mapGen.getIndex()),location);
			setTiles();
			aHold.clear();
			eHold.clear();
		}
		
		//If you just walked out of one dungeon and into another
		if (mapGen.justWarped()){
			//If you have left the exit tile
			if (!mapGen.isExit(mapGen.getIndex(), mainPlay.getPosition())){
				//Then you have no longer just warped, and can warp again immediately
				mapGen.warpExpired();
			}
		}
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		stateTime += Gdx.graphics.getDeltaTime();
		setCharHeight();
		mainPlay.runUpdate(stateTime);
		checkTiles();
		aHold.addCycle();
		for (i = 0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size();i++){
			mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).addCycle();
		}
		for (i = 0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size();i++){
			//If the player is within sight of the enemy, the enemy will chase them
			if(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getSightBox().inSquare(mainPlay.getPosition())){		
				mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).setMovement(mainPlay.getPosition());
			}
			//If the player is within attack range of the enemy, the enemy will attack them
			if(mainPlay.getPosition().inSquare(
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX()-mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getEnemyAttack().getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()-mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getEnemyAttack().getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX()+mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getEnemyAttack().getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()+mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getEnemyAttack().getARange())){
					if(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getCycles()){
						eHold.addAttack(new cPoint(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX(), mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()), 
						new cPoint(mainPlay.getPosition().getX(),mainPlay.getPosition().getY()), mainPlay, mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getEnemyAttack());
					}
				}
			//Is the player in a specified distance away from the enemy?
			//If so, make attack
			if (mainPlay.getPosition().inSquare(
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX()-currentAttack.getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()-currentAttack.getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX()+currentAttack.getARange(), 
					mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()+currentAttack.getARange())){	
				if(aHold.getCycles()){
					aHold.addAttack(new cPoint(mainPlay.getPosition().getX(), mainPlay.getPosition().getY()), 
						new cPoint(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getX(),mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).getPosition().getY()), mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i), currentAttack);
					//sounds.playSound(0);
				}
			}
			
			//Use runUpdate instead of setSprite
			mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).runUpdate(stateTime);
		}
		
		if(mainPlay.isMoving()){
			//walking sound here
			
			//Move camera with player
			resetCamera();
		}
		aHold.incrementAttacks();
		eHold.incrementAttacks();
		
		
		backCam.update();
		cam.update();		
		frontCam.update();

		//This is the code to set the skyBox
		batch.setProjectionMatrix(backCam.combined);
		batch.setTransformMatrix(unmatrix);
		batch.begin();
		
		pointRenderHolder.setPoint(backCam.viewportWidth, backCam.viewportHeight);
		pointRenderHolder2.setPoint(backCam.position.x,backCam.position.y);
		
		sBox.getBox(pointRenderHolder, pointRenderHolder2).draw(batch);
		
		for(i = 0; i < sBox.returnBackgroundSprites().size();i++){
			sBox.returnBackgroundSprites().get(i).draw(batch);
		}
		
		batch.end();
		
		//This the the code to set the game elements
		batch.setProjectionMatrix(cam.combined);
		batch.setTransformMatrix(matrix);
		batch.begin();
		//updateSpriteMap();
		printSprites(batch);

		batch.end();
		
		batch.setProjectionMatrix(frontCam.combined);
		batch.setTransformMatrix(unmatrix);
		batch.begin();
		pointRenderHolder.setPoint(frontCam.viewportWidth, frontCam.viewportHeight);
		gClass.setBox(pointRenderHolder,mainPlay.getLives());
		if (pathFinder){
			gClass.setArrows(pointRenderHolder, texture.returnUtilsArrows());
			for(i = 0; i < gClass.getArrows().length;i++){
				gClass.getArrows()[i].draw(batch);
			}
		}
		gClass.getIcon().draw(batch);
		gClass.getBar().draw(batch);
		//debugHUD.getHUDSprite().draw(batch);

		batch.end();
		
		checkTileTouched();
		checkDeadEnemies();
		checkPlayerDead();
		checkMenu();
		
	}
	@Override
	public void resize(int width, int height) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void show() {
		gameMusic.play();
		numberOfFingers = 0;
		//System.out.println("Show");
		if(g.returnPathfinder()!=pathFinder){
			pathFinder = g.returnPathfinder();
		}
	}
	@Override
	public void hide() {
		gameMusic.stop();
		
	}
	@Override
	public void pause() {
		gameMusic.stop();
		numberOfFingers = 0;
		
	}
	@Override
	public void resume() {
		gameMusic.play();
		//System.out.println("Resume");
		if(g.returnPathfinder()!=pathFinder){
			pathFinder = g.returnPathfinder();
		}
	}
	@Override
	public void dispose() {
		gameMusic.dispose();
		
	}
	public void checkDeadEnemies(){
		//This code checks to make sure that enemies with no health are removed from the map
		deleteFlag = false;
		for(i =0; i < mapGen.getDungeon(mapGen.getIndex()).getEnemies().size(); i++){
			if(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i).returnHealth()>1){
				tempArray.add(mapGen.getDungeon(mapGen.getIndex()).getEnemies().get(i));
			}else{
				deleteFlag = true;
			}
		}
		//Only remake the array if an enemy was defeated
		if(deleteFlag){
			mapGen.getDungeon(mapGen.getIndex()).clearEnemies();
			for(i = 0; i < tempArray.size();i++){
				mapGen.getDungeon(mapGen.getIndex()).addEnemy(tempArray.get(i));
			}
			//tempArray.clear();
		}
		tempArray.clear();
	}
	
	public void setTiles(){
		//Random random = new Random(System.nanoTime());
		//mapGen.getDungeon(mapGen.getIndex()).printFloorMap();
		//Create new sprite array
		resetSprites();
		//Center camera on player's new location
		resetCamera();
		for(z = 0; z < (int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getY()); z++) {
			for(x = 0; x < (int)(mapGen.getDungeon(mapGen.getIndex()).getDimensions().getX()); x++) {
				pointRenderHolder.setPoint(x, z);
				floorSprites[x][z] = mapGen.getFloorProps(mapGen.getIndex(), pointRenderHolder).getSprite();
				if(mapGen.getStructureProps(mapGen.getIndex(), pointRenderHolder).getName().indexOf("null")==-1){
					structures[x][z] = mapGen.getStructureProps(mapGen.getIndex(), pointRenderHolder).getSprite();
				}
			}
		}
	}
}
